
import 'package:syncfusion_flutter_charts/charts.dart';

class CandleData {
  /// The timestamp of this data point, in milliseconds since epoch.
  final int timestamp;

  /// The "open" price of this data point. It's acceptable to have null here for
  /// a few data points, but they must not all be null. If either [open] or
  /// [close] is null for a data point, it will appear as a gap in the chart.
  final double? open;

  /// The "high" price. If either one of [high] or [low] is null, we won't
  /// draw the narrow part of the candlestick for that data point.
  final double? high;

  /// The "low" price. If either one of [high] or [low] is null, we won't
  /// draw the narrow part of the candlestick for that data point.
  final double? low;

  /// The "close" price of this data point. It's acceptable to have null here
  /// for a few data points, but they must not all be null. If either [open] or
  /// [close] is null for a data point, it will appear as a gap in the chart.
  final double? close;

  /// The volume information of this data point.
  final double? volume;

  /// Optional data holder for drawing a trend line, e.g. moving average.
  //double? trend;
  Map<int, double> trends ={};
  //List<double> trends = <double>[];

  CandleData({
    required this.timestamp,
    required this.open,
    required this.close,
    required this.volume,
    this.high,
    this.low,
  });

  static void computeMA(List<CandleData> data, [int period = 7]) {
    if (data.length < period * 2) return;
    final firstPeriod =
        data.take(period).map((d) => d.close).whereType<double>();
    double ma = firstPeriod.reduce((a, b) => a + b) / firstPeriod.length;

    for (int i = period; i < data.length; i++) {
      final curr = data[i].close;
      final prev = data[i - period].close;
      if (curr != null && prev != null) {
        ma = (ma * period + curr - prev) / period;
        //data[i].trend = ma;
        data[i].trends[period] = ma;
      }
    }
  }

  static void computeAll(List<CandleData> data, List<int> periods) {
    //for(var item in data) {
    //  item.trends.clear();
    //}
    for (var p in periods) {
      computeMA(data, p);
    }
  }

  static void deleteMA(List<CandleData> data,  [int period = 7]) {
    //for (var element in data) {
    //  element.trend = null;
    //}
    //for (var element in data) {
    //  element.trends.remove(period);
    //}
  }

  @override
  String toString() => "<CandleData ($timestamp: $close)>";
}

class TrendSeries {
  final int period;
  final double leadingTrend;
   final double trailingTrend;
  final List<double> trends;
    TrendSeries({
    required this.period,
    required this.leadingTrend,
    required this.trailingTrend,
    required this.trends,
  });

  static TrendSeries computeMA(List<CandleData> data, [int period = 7, int start=0, int end=0]) {
    if (data.length < period * 2) return TrendSeries(period: 0, leadingTrend: 0, trailingTrend: 0,trends: []);
    final firstPeriod =
        data.take(period).map((d) => d.close).whereType<double>();
    double ma = firstPeriod.reduce((a, b) => a + b) / firstPeriod.length;

    List<double> trends=[];
    for(int i = 0; i < period; ++i){
      trends.add(double.nan);
    }
    for (int i = period; i < data.length; i++) {
      final curr = data[i].close;
      final prev = data[i - period].close;
      if (curr != null && prev != null) {
        ma = (ma * period + curr - prev) / period;
        //data[i].trend = ma;
        trends.add(ma);
      }
    }
      if (start==0 && end==0) {
    return TrendSeries(
      period: period, 
      leadingTrend: 0, 
      trailingTrend: 0,
      trends: trends);
      } else {
    return TrendSeries(
      period: period, 
      leadingTrend: 0, 
      trailingTrend: 0,
      trends: trends.getRange(start, end).toList(),);
      }

  }
  static List<TrendSeries> computeAll(List<CandleData> data, List<int> periods, [int start=0, int end=0]) {
    List<TrendSeries> lines = <TrendSeries>[];
    for (var element in periods) {
      if (start==0 && end==0) {
      lines.add(computeMA(data, element));
      }
      else {
      lines.add(computeMA(data, element, start, end));
      }
    }
    return lines;
  }

}
